package com.starview.star.operators.ast.runtime;

import com.starview.platform.data.EvaluationException;
import com.starview.platform.data.IArray;
import com.starview.platform.data.IFunction;
import com.starview.platform.data.IValue;
import com.starview.platform.data.type.IType;
import com.starview.platform.data.type.StandardTypes;
import com.starview.platform.data.type.TypeUtils;
import com.starview.platform.data.value.Cons;
import com.starview.platform.data.value.Cons.ConsCons;
import com.starview.platform.data.value.Cons.Nil;
import com.starview.platform.data.value.Factory;
import com.starview.star.compiler.ast.Apply;
import com.starview.star.compiler.ast.IAbstract;
import com.starview.star.operators.CafeEnter;

public class AstReplace implements IFunction
{
  public static final String name = "__astMacroReplace";

  @CafeEnter
  public static IAbstract enter(IAbstract term, Cons path, IAbstract repl) throws EvaluationException
  {
    if (path.equals(Nil.nilEnum))
      return repl;
    else {
      assert path instanceof ConsCons && term instanceof Apply;
      ConsCons consPath = (ConsCons) path;
      Cons tail = (Cons) consPath.get___1();
      Apply app = (Apply) term;
      IAbstract op = app.getOperator();
      IArray args = app.getArgs();
      int ix = Factory.intValue(consPath.get___0());
      if (ix < 0)
        op = enter(op, tail, repl);
      else
        args = args.substituteCell(ix, enter((IAbstract)args.getCell(ix),tail,repl));

      return new Apply(app.getLoc(), op, args, app.getCategories(), app.getAttributes());
    }
  }

  @Override
  public IValue enter(IValue... args) throws EvaluationException
  {
    return enter((IAbstract) args[0], (Cons) args[1], (IAbstract) args[2]);
  }

  @Override
  public IType getType()
  {
    return type();
  }

  public static IType type()
  {
    return TypeUtils.functionType(StandardTypes.astType, TypeUtils.consType(StandardTypes.integerType),
        StandardTypes.astType, StandardTypes.astType);
  }
}
